use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;

use serde::{Deserialize, Serialize};

use crate::db::mysql::ConnectPoolConfig;
use crate::error::{Result,Error};
use std::sync::{Arc, RwLock};

#[derive(Debug,Clone,Deserialize, Serialize)]
pub struct FrameWorkConfig{
    database: Arc<HashMap<String,ConnectPoolConfig>>
}

impl Default for FrameWorkConfig {
    fn default() -> Self {
        let name = "test".to_owned();
        let config = ConnectPoolConfig::default();
        let mut database = HashMap::new();
        database.insert(name,config);
        Self{
            database: Arc::new(database)
        }
    }
}

impl FrameWorkConfig {
    pub fn new() -> Self{
        Self::default()
    }

    pub fn get_database(&self) -> Arc<HashMap<String,ConnectPoolConfig>> {
        self.database.clone()
    }
}

lazy_static::lazy_static!{
    static ref GLOBAL_FRAMEWORK_CONFIG: Arc<RwLock<FrameWorkConfig>> = Arc::new(RwLock::new({

        FrameWorkConfig::default()

    }));
}

pub fn get_db_config() -> Result<Arc<HashMap<String,ConnectPoolConfig>>> {
    let _ref = GLOBAL_FRAMEWORK_CONFIG.clone();
    let guard = _ref.read().map_err(|e|  Error::LockError(format!("get_db_config {:?}",e)))?;
    Ok(guard.get_database())
}

pub fn get_db<'a>(name: &'a str) -> Result<ConnectPoolConfig>{
    let config = get_db_config()?;
    let cur = config.get(name);
    match cur {
        Some(conf) => Ok(conf.clone()),
        None => Err(Error::ConfigLost(format!("db {} config not set yet",name))),
    }
}


pub fn get_all_config_as_string() -> Result<String>{
    let _ref = GLOBAL_FRAMEWORK_CONFIG.clone();
    let guard = _ref.read().map_err(|e|  Error::LockError(format!("get_db_config {:?}",e)))?;
    let serialized = serde_json::to_string(& *guard).unwrap();
    Ok(serialized)
}

pub fn show_conf() -> Result<()>{
    let conf = get_all_config_as_string()?;
    println!("{}",conf);
    Ok(())
}

pub fn load_conf(conf_str: &str) -> Result<()>{    
    let conf: FrameWorkConfig = serde_json::from_str(conf_str)?;
    let _ref = GLOBAL_FRAMEWORK_CONFIG.clone();
    let mut guard = _ref.write().map_err(|e|  Error::LockError(format!("get handle {:?}",e)))?;
    *guard = conf;
    Ok(())
}

pub fn load_conf_by_file(file: &str) -> Result<()>{    
    let handle = File::open(file)?;
    let reader = BufReader::new(handle);
    let conf: FrameWorkConfig = serde_json::from_reader(reader)?;
    let _ref = GLOBAL_FRAMEWORK_CONFIG.clone();
    let mut guard = _ref.write().map_err(|e|  Error::LockError(format!("get handle {:?} when load framework config",e)))?;
    *guard = conf;
    Ok(())
}


#[test]
fn test_show_conf(){
    let _ = show_conf();
}


#[test]
fn load_file_conf(){
    let res = load_conf_by_file("db.json");
    println!("{:?}",res);
    let _ = show_conf();
}
